#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>

#include "functions.c"

pthread_mutex_t mux = PTHREAD_MUTEX_INITIALIZER;
List list;

void *getElement(void * arg) {

	int threadId = (int) arg;
	int tWait = list.tWait[threadId];

	//Tiempo de espera Inicial
	printf("Thread: %d Tiempo Espera Inicial: %d\n", threadId, tWait);
	sleep(tWait);

	while (1) {

		//Preguntar si podemos leer de la lista
		pthread_mutex_lock(&mux);
		pthread_cond_signal(&list.can);

		//Esperar a que updateList nos conteste
		pthread_cond_wait(&list.read, &mux);
		trace(list, threadId);

		//Avisar a updateList que hemos leido un elemento
		pthread_cond_signal(&list.update);
		pthread_mutex_unlock(&mux);

		//Despues de leer, se duerme el thread.
		sleep(tWait);

	}
	pthread_exit(NULL);
	return EXIT_SUCCESS;
}

void *updateList(void * arg) {
	while (1) {

		//Esperar que algun thread quiera leer
		pthread_mutex_lock(&mux);
		pthread_cond_wait(&list.can, &mux);

		//Respondemos que si
		pthread_cond_signal(&list.read);
		pthread_mutex_unlock(&mux);

		//Esperamos hasta que un thread haya leido para actualizar
		pthread_mutex_lock(&mux);
		pthread_cond_wait(&list.update, &mux);
		refreshList(&list);

		//Avisamos al resto de thread que ya pueden volver a leer
		pthread_cond_broadcast(&list.can);
		pthread_mutex_unlock(&mux);

	}
	pthread_exit(NULL);
	return EXIT_SUCCESS;
}

int main(int argc, char *argv[]) {

	int i = 0;
	unsigned int iseed = (unsigned int) time(NULL);
	srand(iseed);
	pthread_t serverThread[NUMPTHREAD];
	pthread_t refreshThread;

	initializeList(&list);

	//Init Mutex Condicionales
	pthread_cond_init(&list.can, NULL);
	pthread_cond_init(&list.read, NULL);
	pthread_cond_init(&list.update, NULL);

	//Create Threads
	for (i = 0; i < NUMPTHREAD; i++) {
		pthread_create(&serverThread[i], NULL, getElement, (void *) i);
	}
	pthread_create(&refreshThread, NULL, updateList, NULL);

	//Join Threads
	for (i = 0; i < NUMPTHREAD; i++) {
		(void) pthread_join(serverThread[i], NULL);
	}
	(void) pthread_join(refreshThread, NULL);

	//Destoy Mutex
	pthread_mutex_destroy(&mux);

	return EXIT_SUCCESS;

}
